package com.bnq.logc.utils

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.widget.Toast
import androidx.core.content.FileProvider
import com.bnq.logc.native.NativeLogc
import java.io.File
import java.text.DecimalFormat
import java.util.regex.Pattern
import kotlin.math.abs


class FileUtil {
    companion object{
        /**
         * 获取文件夹下所有指定文件后缀的文件
         */
        fun getAllFilePath(parentPath:String,suffix:String):List<String>{
            val result = mutableListOf<String>()
            val parentFile = File(parentPath)
            if(!parentFile.exists() || parentFile.isFile){
                return result
            }
            parentFile.listFiles().forEach { file ->
                val path = file.absolutePath
                if(path.endsWith(suffix)){
                    result.add(path)
                }
            }
            return result
        }

        fun getAllFile(parentPath:String,suffix:String):List<File>{
            return getAllFile(File(parentPath),suffix)
        }

        /**
         * 获取文件夹下所有指定文件后缀的文件
         */
        fun getAllFile(parentFile:File,suffix:String):List<File>{
            if(!parentFile.exists() || parentFile.isFile){
                return emptyList()
            }
            return parentFile.listFiles { pathname->
                pathname.path.endsWith(suffix)
            }?.toList() ?: emptyList()
        }

        fun findFiles(parentFile:File,predicate: (File) -> Boolean):List<File>{
            if(!parentFile.exists() || !parentFile.isDirectory){
                return emptyList()
            }
            val files: MutableList<File> = ArrayList()
            if (parentFile.exists() && parentFile.isDirectory) {
                val listFiles = parentFile.listFiles()
                if(listFiles != null){
                    for (file in listFiles) {
                        if (file.isDirectory) {
                            files.addAll(findFiles(file,predicate))
                        } else {
                            if(predicate(file)){
                                files.add(file)
                            }
                        }
                    }
                }
            }
            return files
        }

        /**
         * 获取{count}个最新的文件,按照文件名排序
         * parentFile：父文件夹
         * suffix：获取的文件后缀
         * count：获取的文件个数
         */
        fun getLastFiles(parentFile: File, suffix:String = "",count:Int = 7): List<File> {
            if(!parentFile.exists() || !parentFile.isDirectory || count <= 0){
                return emptyList()
            }
            val files: MutableList<File> = ArrayList()
            if (parentFile.exists() && parentFile.isDirectory) {
                val listFiles = parentFile.listFiles()
                if(listFiles != null){
                    listFiles.apply {
                        sortBy { it.name }
                        reverse()
                    }
                    for (file in listFiles) {
                        if (file.isDirectory) {
                            files.addAll(getLastFiles(file,suffix,count - files.size))
                        } else {
                            if(suffix.isNotBlank()){
                                if(file.name.endsWith(suffix)){
                                    files.add(file)
                                }
                            }else{
                                files.add(file)
                            }
                        }
                        if(files.size >= count){
                            break
                        }
                    }
                }
            }
            return if (files.size > count) files.subList(0, count) else files
        }

        fun getFileKey(file: File):String{
            return file.name
        }

        fun getDateFromName(file: File):String?{
            val name = file.name
            val split = name.split(".")
            if(split.size >= 2){
                 if(Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$").matcher(split[0]).matches()){
                     return split[0]
                 }
            }
            return null
        }

        fun checkStringIsDate(str:String):Boolean{
            return Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$").matcher(str).matches()
        }

        fun isTodayFile(file: File):Boolean{
            return file.name.startsWith(DateUtil.getCurrentYMDString())
        }

        /**
         * 是否是一周内的文件
         */
        fun isWeekFile(file: File):Boolean{
            val date = getDateFromName(file)?:return false
            return abs(DateUtil.getDiffDaysToNow(date)) <= 7
        }

        //只删除文件，不删除文件夹
        fun deleteFilesNotDir(dirPath: String?): Boolean = if (dirPath.isNullOrBlank()) false else deleteFilesNotDir(File(dirPath))

        //只删除文件，不删除文件夹
        fun deleteFilesNotDir(dir: File?): Boolean {
            if (dir == null || !dir.exists() || !dir.isDirectory) return false

            val children = dir.list()
            if (children.isNullOrEmpty()) return true

            val len = children.size
            var child: File?
            for (i in 0 until len) {
                child = File(dir, children[i])
                val success: Boolean = if (child.isDirectory) {
                    if (child.list() == null || child.list()?.isEmpty() == true) {
                        continue
                    }
                    deleteFilesNotDir(child)
                } else {
                    child.delete()
                }
                if (!success) return false
                if (i == len - 1) return true
            }
            return false
        }

        fun deleteFilesAction(dirPath: String?,predicate: (File) -> Boolean){
            if (!dirPath.isNullOrBlank()) deleteFilesAction(File(dirPath),predicate)
        }

        fun deleteFilesAction(dir: File?,predicate: (File) -> Boolean){
            if (dir == null || !dir.exists() || !dir.isDirectory) return

            val children = dir.list()
            if (children.isNullOrEmpty()) return

            val len = children.size
            var child: File?
            for (i in 0 until len) {
                child = File(dir, children[i])
                if (child.isDirectory) {
//                    if (child.list() == null || child.list()?.isEmpty() == true) {
//                        child.delete()
//                        continue
//                    }
                    deleteFilesAction(child,predicate)
                } else {
                    if(predicate.invoke(child)){
                        child.delete()
                    }
                }
            }
        }

        /**
         * 移除超过指定期限的文件(Remove files older than specified age)
         * eg: 移除超过一个月的文件(Remove files older than a month) maxFileAge=2678400000L
         *
         * @param directoryPath 期限
         */
        fun deleteFilesOutDate(directoryPath: String, maxFileAge: Long = 2678400000L) {
            // Used to examplify deletion of files more than 1 month old
            // Note the L that tells the compiler to interpret the number as a Long
            val MAXFILEAGE = maxFileAge // 1 month in milliseconds
            // Get file handle to the directory. In this case the application files dir
            val dir: File = File(directoryPath)
            // Obtain list of files in the directory.
            // listFiles() returns a list of File objects to each file found.
            val files = dir.listFiles()
            if (files.isNullOrEmpty()) return
            // Loop through all files
            for (f in files) {
                // Get the last modified date. Milliseconds since 1970
                val lastModified = f.lastModified()
                // Do stuff here to deal with the file..
                // For instance delete files older than 1 month
                if (lastModified + MAXFILEAGE < System.currentTimeMillis()) {
                    f.delete()
                }
            }
        }

        //删除文件或文件夹
        fun deleteFile(pathAndName: String?): Int =
            if (pathAndName.isNullOrBlank()) 0
            else deleteFileWithoutExcludeNames(File(pathAndName), null)

        /**
         * 删除文件或文件夹
         *
         * Delete files or directories
         *
         * @param file
         * @return Int 删除`文件/文件夹`数量 (Delete the number of `file folders`)
         */
        fun deleteFile(file: File?): Int = deleteFileWithoutExcludeNames(file, null)

        /**
         * 删除文件或文件夹
         *
         * Delete files or directories
         * <p>
         *     建议异步处理
         *
         * @param file  `文件/文件夹`
         * @param excludeFiles 指定名称的一些`文件/文件夹`不做删除 (Some `files/directory` with specified names are not deleted)
         * @return Int 删除`文件/文件夹`数量 (Delete the number of `file folders`)
         */
        fun deleteFileWithoutExcludeNames(file: File?, vararg excludeFiles: String?): Int {
            var count = 0
            if (file == null || !file.exists()) return count
            if (file.isDirectory) {
                val children = file.listFiles()
                if (children.isNullOrEmpty() && shouldFileDelete(file, *excludeFiles)) {
                    if (file.delete()) count++ //delete directory
                } else {
                    var i = 0
                    while (children != null && i < children.size) {
                        count += deleteFileWithoutExcludeNames(children[i], null)
                        i++
                    }
                }
            }
            if (excludeFiles.isNullOrEmpty()) {
                if (file.delete()) count++
            } else {
                if (shouldFileDelete(file, *excludeFiles)) if (file.delete()) count++
            }
            return count
        }

        private fun shouldFileDelete(file: File, vararg excludeFiles: String?): Boolean {
            var shouldDelete = true
            excludeFiles.forEach {
                shouldDelete = (it?.equals(file.name, true) != true)
                if (shouldDelete) return@forEach
            }
            return shouldDelete
        }

        /**
         * 获取文件名或者父文件夹名或者文件创建时间戳对应的时间戳
         * parseFileCreateTime：是否解析文件创建时间对应的时间戳
         * parsePreParentPathName：是否解析父文件夹名对应的时间戳
         */
        fun getFileNameToTimestamp(file: File,parseFileCreateTime:Boolean = true,parsePreParentPathName:Boolean = false):Long?{
            var createTime = getDateFromName(file)
            if(createTime != null){
                val timestamp = DateUtil.timeToTimestampYMD(createTime)
                if(timestamp > 0){
                    return timestamp
                }
            }
            if(parsePreParentPathName){
                val parentName = file.parentFile?.name?:""
                if(checkStringIsDate(parentName)){
                    val timestamp = DateUtil.timeToTimestampYMD(parentName)
                    if(timestamp > 0) {
                        return timestamp
                    }
                }
            }
            if(!parseFileCreateTime){
                return null
            }
            val timestamp = NativeLogc.getFileCreateTimeStamp(file)
            if(timestamp > 0){
                return timestamp
            }
            return null
        }

        /**
         * 转换文件大小
         * @param files
         * @return
         */
        fun formatFileSize(files: Long): String {
            val df = DecimalFormat("#.00")
            var fileSizeString = ""
            val wrongSize = "0B"
            if (files == 0L) {
                return wrongSize
            }
            fileSizeString = if (files < 1024) {
                df.format(files.toDouble()) + "B"
            } else if (files < 1048576) {
                df.format(files.toDouble() / 1024) + "KB"
            } else if (files < 1073741824) {
                df.format(files.toDouble() / 1048576) + "MB"
            } else {
                df.format(files.toDouble() / 1073741824) + "GB"
            }
            return fileSizeString
        }

        fun getUriForFile(context: Context, file: File): Uri {
            return if (Build.VERSION.SDK_INT >= 24) {
                FileProvider.getUriForFile(context,context.packageName + ".android7.fileprovider", file)
            } else {
                Uri.fromFile(file)
            }
        }

        fun openTextFile(context: Context,filePath: String) {
            // 创建一个Intent对象，动作设置为ACTION_VIEW以表示查看操作
            val intent = Intent(Intent.ACTION_VIEW)

            // 设置Intent的数据类型为text/plain，表示打开纯文本文件
            val uri = getUriForFile(context, File(filePath))
            intent.setDataAndType(uri, "text/plain")
            intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION

            // 检查设备上是否有适合的应用程序来处理此Intent
            if (intent.resolveActivity(context.packageManager) != null) {
                // 如果有适合的应用程序，则启动该Intent
                context.startActivity(intent)
            } else {
                // 如果没有适合的应用程序，则显示一条消息提示用户安装文本查看器
                // 可以根据需要修改此消息
                Toast.makeText(context, "没有找到适合的应用程序来查看文本文件", Toast.LENGTH_SHORT)
                    .show()
            }
        }

        fun generateFileNameByOriginFileName(srcName:String,append:String = ".plaintext"):String{
            val index = srcName.lastIndexOf(".")
            return if(index > 0){
                srcName.substring(0,index) + append + srcName.substring(index)
            }else{
                srcName + append
            }
        }

        fun checkFileOriginal(fileName:String):Boolean{
            val name = fileName
            return Pattern.compile("^\\d{4}-\\d{2}-\\d{2}.log$").matcher(name).matches()
        }

        fun isHasOriginFileForParentDir(parentFile: File?):Boolean{
            return parentFile?.listFiles()?.find { checkFileOriginal(it.name) }?.let {
                return true
            }?:false
        }

        fun isOriginFilePath(parentPath:String,filePath:String):Boolean{
            return filePath.startsWith(parentPath)
        }

    }
}